""" turn names for python objects into links """
import os.path
    
def findmodule(pkgpth, pythonobject):
    """ guesses where an object is found in the package
    
            pkgpath:      str, absolute path to the package to search
            pythonobject: str, a dotted object spec including packages and subpackages
                          e.g "package.subpkg.module.class.method"
            
        returns (modulepth, actual_object) where
            modulepth is a str giving he absolute path to the module which MIGHT contain the dotted object, with:
                      - os.path.sep as the separator
                      - no extension (.py etc) given  
            actual_object is a str giving the possibly-dotted object name:
                     - this may be ""
                     - there is no check that it actually exists in the module specified by modulepth!
            
            or (None, None) if if no candidate was identified
            
            e.g.
                ("c:\package\subpkg\module", "class.method")
    """
    #print 'pythonobject:', pythonobject
    basepth, pkgname = os.path.split(pkgpth)
    tarparts = pythonobject.split('.')
    
    if tarparts[0] != pkgname:
        return (None, None)
        
    # work backwards chopping off bits till we find one which exists
    for i in range(len(tarparts), 0, -1):
        modulepth = os.path.join(basepth, *tarparts[:i])
        if os.path.isfile(modulepth + '.py'):
            object = '.'.join(tarparts[i:]) #str, possibly empty
            return (modulepth, object)
        elif os.path.isdir(modulepth):
            #print 'found matching dir:', modulepth
            object = '.'.join(tarparts[i:]) #str, possibly empty
            modulepth = modulepth + os.path.sep + '__init__'
            return (modulepth, object)
        
        #else:
        #    print 'tried:', modulepth
            
    # or didn't find a match:
    print "no match for", pythonobject
    return (None, None)
    

class APILinker(object):
    """ like epydoc.markup.DocstringLinker
    
        Links are generated by the rst markup `object` or `label<object>`, where object may be dotted.
        
        The object may either be specfied in full, i.e. starting from the package name, or just the object itself, in which
        case the object is assumed to be in the current module.  Links to modules must always be given in full.
        
        Note that whether objects actually exist in the given sub-package/module isn't checked.
        
        Trailing "()" is stripped from the link.
        
        so what if we have:
        subpackage1/
            __init__.py containing
                thing = subpackage2.submodule.object
        
        can we link to subpackage1.thing?
        
        No - we link to subpackage.__init__.thing
        
        Then because we don't actually find the object, as long as we pick up module level variables and add an id to these
        this will work!
        
        Can we automatically resolve subpackage.thing to subpackage.__init__.thing?
        Maybe - we would need to identify that the LAST element in the current path we're checking is a dir
        and add __init__.py to it.
        
        Can we get a clash bewteen subpackage1.__init__.thing and subpackage/thing.py?
        I don't think so because Python would also be confused.
        
        TODO:
        - handle links to __init__.py
        - handle links to the top of modules - this works at the moment, but isn't gauranteed to.
        
        The generated IDs expect that objects have ids ("pyid" in the templates) as follows:
            module: modulename_full
            property, constructor, instancemethod :pyclassname.funcname
            class: pyclassname
            function: funcname
    """
    
    def __init__(self, modulepth, packagepth=None):
        self.pkgpth = packagepth
        self.moduledir = os.path.dirname(modulepth)
        
    def translate_identifier_xref(self, identifier, label=None):
        """NB identifier and label seem to be the same """
        
        if identifier != label:
            print 'OOPS! linker: identifier="%s", label="%s"' % (identifier, label)
            exit()
        
        text = identifier
        
        if '&lt;' in text and text.endswith('&gt;'): # have`linktext<object>`
            linktxt, target  = text.split('&lt;')
            target = target[:-4]
        else:
            linktxt = text
            target = text
        
        if target.endswith('()'):
            target = target[:-2]
        #print 'linktxt="%s", target="%s"' % (linktxt, target)
        # try to find the target in the package being documented:
        (tgtmodulepth, objectspec) = findmodule(self.pkgpth, target)
            
        # if its not found in the package..
        if not self.pkgpth or not tgtmodulepth:
             # TODO: try looking in builtins?
             # then assume its a local link on the same page:
             #print 'assuming internal link: linktxt="%s", target="%s"' % (linktxt, target)
             link = '<a href="#%s">%s</a>' % (target, linktxt)
             
        else:
            url = os.path.relpath(tgtmodulepth, self.moduledir)
            if os.path.sep == '\\':
                url = url.replace('\\', '/')  ## not sure this is quite right, what if we have actual \\ in the path?
            if url == '': # target is then current module, 
                #  make an internal link to the object (which we assume exists)
                #print 'internal link from full spec: linktxt="%s", refid="%s"' % (linktxt, objectspec)
                link =  '<a href="#%s">%s</a>' % (objectspec, linktxt)
            else:
                url += '.html'
                url += '#%s' % objectspec if objectspec else ''
                link =  '<a href="%s">%s</a>' % (url, linktxt)
                #print 'full link: url="%s", linktxt="%s"' % (url, linktxt)
                
        return link
    
    def translate_indexterm(self, indexterm):
        raise NotImplementedError()
    
    def url_for(self, identifier):
        raise NotImplementedError()